home *** CD-ROM | disk | FTP | other *** search
- /*######################################################################################
- ## ResourceNode Functions & Structures, by Leo Davidson ##
- ## Functions for easy allocation, openning, closing, freeing, etc. ##
- ## ##
- ## This version uses the memory pool routines in dopus5.library, not the exec ones. ##
- ## ##
- ## Tabsize: 4 -- Amiga-specific -- Compile with SAS/C. ##
- ########################################################################################
- $VER: ResourceNodes.c 1.2 (2.10.96)
-
- All routines take a pointer to a ResNode_Data structure. Initially, this
- should be all NULLs except for poolhead which must be set up as the Header
- for a memory pool. MEMF_CLEAR *must* be turned on for this pool.
- It is up to you to free the pool once you're finished using ResNodes.
- Other routines are free to use the pool, but if you have more than one pointer
- to it, make sure they all get NULLed when the pool is freed.
-
- All close/free/etc. routines should be safe to call when nothing needs to be
- closed/freed/etc.
-
- ****************************************************************************************
-
- Although these routines and related structures are more-or-less stand alone, the
- intention is that a customised version of them will be used for each project. This
- means that one isn't tied down by forced compatibility with other situations and
- environments.
-
- ***************************************************************************************/
-
- #include "compare.module.h"
-
- /*====================================================================================-.
- || Optional Functions ||
- `-====================================================================================*/
- #define ResNodes_Allocate
- #define ResNodes_Lock
- #define ResNodes_Examine
- #define ResNodes_Open
- #define ResNodes_DeleteFile
-
- /**************************************************************************************/
-
- /*= CreateResNode() ==================================================================-.
- || Attempts to allocate a new ResNode structure. Returns pointer to new, cleared ||
- || ResNode, or NULL on failure. Updates the linked list of ResNodes. ||
- `-====================================================================================*/
- ResNode *createResNode(ResNode_Data *rnd)
- {
- ResNode *newResNode;
-
- if ( newResNode = AllocMemH(rnd->poolhead,sizeof(ResNode)) )
- {
- newResNode->rn_Next = rnd->resnode_base; // Update list pointers
- if (rnd->resnode_base)
- rnd->resnode_base->rn_Prev = newResNode;
- rnd->resnode_base = newResNode;
- }
- return newResNode;
- }
-
- /*= DeleteResNode() ==================================================================-.
- || Delete a ResNode and all free all things connected with it. ||
- || You should not use the ResNode pointer's value again after calling this routine. ||
- || ||
- || Note: Failure to close/deallocate/whatever anything may result in a requester to ||
- || the user but will not cause a different return value. ||
- `-====================================================================================*/
- void deleteResNode(ResNode_Data *rnd, ResNode *doomedResNode)
- {
- if (doomedResNode)
- {
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
- /* Insert calls to new close/deallocate/whatever functions here. */
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
- #ifdef ResNodes_Lock
- unlockFileResNode(rnd,doomedResNode);
- #endif
- #ifdef ResNodes_Examine
- freeFIBResNode(rnd,doomedResNode);
- #endif
- #ifdef ResNodes_Open
- closeFileResNode(rnd,doomedResNode);
- #endif
- #ifdef ResNodes_DeleteFile
- // Only automatically delete the file if rn_TempFile is set.
- if (doomedResNode->rn_TempFile)
- deleteFileResNode(rnd,doomedResNode);
- #endif
- // Deallocation must be done AFTER the file has been deleted because the filename
- // may be allocated in the same ResNode!
- #ifdef ResNodes_Allocate
- freeMemResNode(rnd,doomedResNode);
- #endif
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
- // Unlink it from the list.
- if (doomedResNode->rn_Prev)
- (doomedResNode->rn_Prev->rn_Next) = doomedResNode->rn_Next;
- else
- rnd->resnode_base = doomedResNode->rn_Next; // If no Prev it's head of the list.
-
- if (doomedResNode->rn_Next)
- (doomedResNode->rn_Next->rn_Prev) = doomedResNode->rn_Prev;
-
- // Free the memory for the ResNode itself.
- FreeMemH(doomedResNode);
- }
- }
-
- /*= DeleteAllResNodes() ==============================================================-.
- || Delete ALL ResNodes and free all things connected with them. ||
- `-====================================================================================*/
- void deleteAllResNodes(ResNode_Data *rnd)
- {
- while (rnd->resnode_base)
- deleteResNode(rnd,rnd->resnode_base);
- }
-
- #ifdef ResNodes_Allocate
- /*= AllocMemResNode() ================================================================-.
- || Allocate some memory for a ResNode. ||
- || Returns pointer to allocated memory, or NULL on failure. ||
- || Memory will be cleared automatically. ||
- `-====================================================================================*/
- void *allocMemResNode(ResNode_Data *rnd,ResNode *daddyResNode,ULONG memSize)
- {
- void *amrn_return = NULL;
-
- if (daddyResNode->rn_Mem)
- {
- // Should never allocate twice for one ResNode.
- informUser(rnd->data, TEXT_INTERNAL_ERROR, FALSE, NULL);
- }
- else
- {
- if ((daddyResNode->rn_Mem) = AllocMemH(rnd->poolhead,memSize))
- (daddyResNode->rn_Size) = memSize;
- else
- (daddyResNode->rn_Size) = 0;
-
- amrn_return = (daddyResNode->rn_Mem);
- }
-
- return (amrn_return);
- }
- //--- Part of #ifdef above ---
- /*= AllocNewResNode() ================================================================-.
- || Create a new ResNode and Allocate memory for it. ||
- || Returns NULL on failure. ||
- `-====================================================================================*/
- ResNode *allocNewResNode(ResNode_Data *rnd,ULONG memSize)
- {
- ResNode *babyResNode;
-
- if (babyResNode = createResNode(rnd))
- {
- if (!(allocMemResNode(rnd,babyResNode,memSize)))
- {
- deleteResNode(rnd,babyResNode);
- babyResNode = NULL;
- }
- }
- return babyResNode;
- }
- //--- Part of #ifdef above ---
- /*= FreeMemResNode() =================================================================-.
- || Free memory allocated for a ResNode. ||
- || Resets rn_Mem and rn_Size to NULL. ||
- `-====================================================================================*/
- void freeMemResNode(ResNode_Data *rnd,ResNode *dietResNode)
- {
- if (dietResNode->rn_Mem) // Don't free if nothing to free).
- FreeMemH(dietResNode->rn_Mem);
-
- dietResNode->rn_Size = (ULONG)(dietResNode->rn_Mem = NULL);
- }
- #endif
-
- #ifdef ResNodes_Lock
- /*= lockFileResNode() ================================================================-.
- || Attempts to lock the ResNode's file (rn_Name) with the given mode. ||
- || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
- || RN_INUSE_DELAY seconds between each try. ||
- || Lockmode should be either ACCESS_READ or ACCESS_WRITE. ||
- || Returns the lock, or NULL on failure. ||
- `-====================================================================================*/
- BPTR lockFileResNode(ResNode_Data *rnd,ResNode *rn,LONG lockmode)
- {
- BPTR lfrn_return = NULL;
- int i;
-
- // Internal error if no ResNode, no filename or already locked.
- if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_Lock) )
- informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
- else
- {
- i = 0;
- while ( (i <= RN_INUSE_RETRIES) && \
- ( !(rn->rn_Lock = Lock(rn->rn_Name,lockmode)) ) )
- {
- if (IoErr() != ERROR_OBJECT_IN_USE)
- i = RN_INUSE_RETRIES + 1; // Don't try any more times.
- else
- {
- i++;
- Delay(50 * RN_INUSE_DELAY);
- }
- }
- lfrn_return = (rn->rn_Lock);
- }
- return(lfrn_return);
- }
- //--- Part of #ifdef above ---
- /*= unlockFileResNode() ==============================================================-.
- || Frees the ResNode's file lock, if it has one. ||
- || Passing a NULL ResNode or a ResNode with no lock is harmless. ||
- `-====================================================================================*/
- void unlockFileResNode(ResNode_Data *rnd,ResNode *lockedResNode)
- {
- if ( (lockedResNode) && (lockedResNode->rn_Lock) )
- {
- UnLock(lockedResNode->rn_Lock);
- lockedResNode->rn_Lock = NULL;
- }
- }
- #endif
-
- #ifdef ResNodes_Examine
- /*= examineResNode() =================================================================-.
- || Attempts to allocate and fill-in the FileInfoBlock (rn_FIB) for a ResNode. ||
- || If the ResNode doesn't have a file lock already one will be obtained in READ mode ||
- || (this requires a valid filename in the ResNode). ||
- || If anything fails, memory allocated for the FIB will be freed and the lock, if ||
- || created by this routine, will be freed. ||
- || Returns pointer to FIB, or NULL on failure. ||
- `-====================================================================================*/
- struct FileInfoBlock *examineResNode(ResNode_Data *rnd,ResNode *rn)
- {
- BPTR wegotlock = NULL;
- void *ern_return = NULL;
-
- // Internal error if no ResNode, no filename or already examined.
- if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FIB) )
- informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
- else
- {
- // First, allocate a File Info Block.
- if (rn->rn_FIB = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL))
- {
- // If there isn't a lock, get one in READ mode and remember that this
- // routine got the lock so it'll get freed if the Examine() fails.
- if ( (rn->rn_Lock) || (wegotlock = lockFileResNode(rnd,rn,ACCESS_READ)) )
- {
- if ( !(Examine(rn->rn_Lock,rn->rn_FIB)) )
- {
- // If we couldn't do the Examine(), free what we allocated.
- FreeDosObject(DOS_FIB,rn->rn_FIB);
- (rn->rn_FIB) = NULL;
- if (wegotlock)
- unlockFileResNode(rnd,rn);
- }
- }
- // If we couldn't do the Lock(), free what we allocated.
- else
- {
- FreeDosObject(DOS_FIB,rn->rn_FIB);
- (rn->rn_FIB) = NULL;
- }
- }
- ern_return = (rn->rn_FIB);
- }
- return(ern_return);
- }
- //--- Part of #ifdef above ---
- /*= freeFIBResNode() =================================================================-.
- || Frees ResNode's FileInfoBlock (rn_FIB). ||
- || Does *NOT* unlock the ResNode's lock, even if examineResNode got the lock. ||
- || Passing a NULL ResNode or a ResNode with no FIB is harmless. ||
- `-====================================================================================*/
- void freeFIBResNode(ResNode_Data *rnd,ResNode *rn)
- {
- if ( (rn) && (rn->rn_FIB) )
- {
- FreeDosObject(DOS_FIB,rn->rn_FIB);
- (rn->rn_FIB) = NULL;
- }
- }
- #endif
-
- #ifdef ResNodes_Open
- /*= openFileResNode() ================================================================-.
- || Attempts to open the ResNode's file (using rn_Name as the filename). ||
- || mode must be MODE_OLDFILE, MODE_NEWFILE, or MODE_READWRITE (shared but can create).||
- || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
- || RN_INUSE_DELAY seconds between each try. ||
- || Returns file handle, or NULL on failure. ||
- ||------------------------------------------------------------------------------------||
- || Note that it is safe to open a ResNode file where the filename is in rn_Mem, too, ||
- || even if you set rn_TempFile, as ResNode memory is freed *after* the file is ||
- || deleted (if required) in deleteResNode(). Of course, you must make sure you don't ||
- || free the filename memory if the file will be deleted later explicitly by you or ||
- || implicitly by deleteResNode(). ||
- `-====================================================================================*/
- BPTR openFileResNode(ResNode_Data *rnd,ResNode *rn,LONG mode)
- {
- BPTR ofrn_return = NULL;
- int i;
-
- // Internal error if no ResNode, no filename or already openned.
- if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FHandle) )
- informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
- else
- {
- i = 0;
- while ( (i <= RN_INUSE_RETRIES) && \
- ( !((rn->rn_FHandle) = Open(rn->rn_Name,mode)) ) )
- {
- if (IoErr() != ERROR_OBJECT_IN_USE)
- i = RN_INUSE_RETRIES + 1; // Don't try any more times.
- else
- {
- i++;
- Delay(50 * RN_INUSE_DELAY);
- }
- }
- ofrn_return = (rn->rn_FHandle);
- }
- return(ofrn_return);
- }
- //--- Part of #ifdef above ---
- /*= closeFileResNode() ===============================================================-.
- || Closes the ResNode's file. ||
- || Doesn't bother checking whether or not it failed. (What's it meant to do if it ||
- || does, huh?) ||
- || Passing a NULL ResNode or a ResNode with NULL file handle is harmless. ||
- `-====================================================================================*/
- void closeFileResNode(ResNode_Data *rnd,ResNode *rn)
- {
- if ( (rn) && (rn->rn_FHandle) )
- {
- Close(rn->rn_FHandle);
- (rn->rn_FHandle) = NULL;
- }
- }
- #endif
-
- #ifdef ResNodes_DeleteFile
- /*= deleteFileResNode() ==============================================================-.
- || Deletes the ResNode's file (rn_Name). ||
- || This routine will only be called automatically on ResNodes with rn_TempFile set. ||
- || Passing a NULL ResNode or a ResNode with no filename is harmless. ||
- || Passing a ResNode with rn_Name pointing to invalid/freed memory is not! ||
- || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting ||
- || RN_INUSE_DELAY seconds between each try. ||
- || If the file cannot be deleted nothing special will happen and the file'll be left. ||
- ||------------------------------------------------------------------------------------||
- || Note that it is safe to open a ResNode file where the filename is in rn_Mem, too, ||
- || even if you set rn_TempFile, as ResNode memory is freed *after* the file is ||
- || deleted (if required) in deleteResNode(). Of course, you must make sure you don't ||
- || free the filename memory if the file will be deleted later explicitly by you or ||
- || implicitly by deleteResNode(). ||
- `-====================================================================================*/
- void deleteFileResNode(ResNode_Data *rnd,ResNode *rn)
- {
- int i;
-
- if ( (rn) && (rn->rn_Name) )
- {
- i = 0;
-
- while ( (i <= RN_INUSE_RETRIES) && (!(DeleteFile(rn->rn_Name))) )
- {
- if (IoErr() != ERROR_OBJECT_IN_USE)
- i = RN_INUSE_RETRIES + 1; // Don't try any more times.
- else
- {
- i++;
- Delay(50 * RN_INUSE_DELAY);
- }
- }
- }
- }
- #endif
-